//-
// ==========================================================================
// Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All
// rights reserved.
//
// The coded instructions, statements, computer programs, and/or related
// material (collectively the "Data") in these files contain unpublished
// information proprietary to Autodesk, Inc. ("Autodesk") and/or its
// licensors, which is protected by U.S. and Canadian federal copyright
// law and by international treaties.
//
// The Data is provided for use exclusively by You. You have the right
// to use, modify, and incorporate this Data into other products for
// purposes authorized by the Autodesk software license agreement,
// without fee.
//
// The copyright notices in the Software and this entire statement,
// including the above license grant, this restriction and the
// following disclaimer, must be included in all copies of the
// Software, in whole or in part, and all derivative works of
// the Software, unless such copies or derivative works are solely
// in the form of machine-executable object code generated by a
// source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
// AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED
// WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF
// NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
// PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR
// TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS
// BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
// DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK
// AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY
// OR PROBABILITY OF SUCH DAMAGES.
//
// ==========================================================================
//+

//	File Name: stereoCameraViewCmd.cpp
//
//	Description:
//    Demonstrates how to setup a MPx3dModelView with stereoscopic support.
//    You graphics card must support stereo buffers.
//
//    This is the main command for creating MPx3dModelViews. This commands
//    only acts as an interface to the actual viewport. It is derived 
//    off of MPxModelEditorCommand. 
//
//	Date:	Oct 2 2006
//

#include <stereoCameraViewCmd.h>

#include <maya/MItDag.h>
#include <maya/MGlobal.h>
#include <maya/MSyntax.h>
#include <maya/MArgParser.h>
#include <maya/MArgList.h>
#include <maya/MSelectionList.h>
#include <maya/MFnCamera.h>

#include <maya/MIOStream.h> 

stereoCameraViewCmd::stereoCameraViewCmd()
: 	MPxModelEditorCommand()
//
//	Description:
//		Class constructor.
//
{
}

stereoCameraViewCmd::~stereoCameraViewCmd()
//
//	Description:
//		Class destructor.
//
{
}

void* stereoCameraViewCmd::creator()
//
//	Description:
//		Creator function for this command. 
//
{
    return new stereoCameraViewCmd();
}

MPx3dModelView *stereoCameraViewCmd::userView()
//
//	Description:
//      Creator funcation for the panel view.  This is the 3dGraphics view. 
//
{
    return new stereoCameraView();
}

MStatus stereoCameraViewCmd::appendSyntax()
//
//	Description:
//		Add syntax to the command. All of the parent syntax is added
//		before this call is made. Be careful not to add flags that already
//		exist in the base class (see modelEditor command for more information).
//
{
	MStatus ReturnStatus;

	MSyntax theSyntax = syntax(&ReturnStatus);
	if (MS::kSuccess != ReturnStatus) {
		MGlobal::displayError("Could not get the parent's syntax");
		return ReturnStatus;
	}

	theSyntax.addFlag( kLeftEyeCameraFlag, kLeftEyeCameraFlagLong, 
					   MSyntax::kString );
	theSyntax.addFlag( kRightEyeCameraFlag, kRightEyeCameraFlagLong, 
					   MSyntax::kString ); 
	theSyntax.addFlag( kCenterCameraFlag, kCenterCameraFlagLong, 
					   MSyntax::kString );
	theSyntax.addFlag( kDisplayModeFlag, kDisplayModeFlagLong, 
					   MSyntax::kString ); 
	theSyntax.addFlag( kSwapBufferFlag, kSwapBufferFlagLong );
	theSyntax.addFlag( kOverrideAdornmentDrawFlag, 
					   kOverrideAdornmentDrawFlagLong, 
					   MSyntax::kBoolean  ); 
	theSyntax.addFlag( kOverrideHUDDrawFlag, 
					   kOverrideHUDDrawFlagLong, 
					   MSyntax::kBoolean ); 
	
	return ReturnStatus;
}

MStatus stereoCameraViewCmd::doEditFlags()
//
//	Description:
//		Handle edits for flags added by this class.  If the flag is
//		known, return MS::kSuccess after processing the flag.
//		Returning MS::kUnknownParameter will cause the parent class to
//		process the flag.
//
{
	MStatus ReturnStatus = MS::kSuccess;

	MPx3dModelView *user3dModelView = modelView();
	if (NULL == user3dModelView ||
		user3dModelView->viewType() != "stereoCameraView") {
		MGlobal::displayError("Not a stereo camera view!");
		// Depending on your class structure, will dictate how you 
		// handle this case. If you have additional classes derived
		// from MPx3dModelViewCommand you should always call the
		// parent class doEditFlags to allow base classes to handle
		// any flags.  In this case, returning MS::kUnknownParameter 
		// tells the API that it should call the parent class.  
		//
		return MS::kUnknownParameter;
	}

	// This is now safe to do, since the above test passed. It is very
	// important that you have an unique string describing your custom
	// view. If you do not have a unique name, then it is impossible
	// to know when you are dealing with the proper view.
	//
	stereoCameraView *mpView = (stereoCameraView *)user3dModelView;

	MArgParser argData = parser();
	if ( argData.isFlagSet(kDisplayModeFlag) ) {
		// Check the display mode. This will dictate how stereo data
		// is rendered in the view port. 
		//    
		MString displayMode; 
		argData.getFlagArgument( kDisplayModeFlag, 0, displayMode );
		if ( displayMode == kStereoMode ) { 
			mpView->setDisplayMode( stereoCameraView::kStereo ); 
		} else if ( displayMode == kLeftEye ) { 
			mpView->setDisplayMode( stereoCameraView::kLeftCamera );
		} else if ( displayMode == kRightEye ) { 
			mpView->setDisplayMode( stereoCameraView::kRightCamera ); 
		} else if ( displayMode == kCenterEye ) { 
			mpView->setDisplayMode( stereoCameraView::kCenterCamera );
		} else { 
			MGlobal::displayError( "Invalid display mode" ); 
			return MS::kFailure; 
		}
	}


	// The next set of flags check for changes to the camera settings.
	// We need the user to specify the left, right, and center camera.
	// The center camera is useful for viewing the scene when stereo
	// is "off".  Note, stereo is never really off. We are simplying
	// drawing the same buffer into the left & right image to give the
	// appearance of no stereo. 
	//  
	// Currently there is not a lot of checking to verify that the 
	// camera you specified is actually valid.  If an invalid camera
	// is specified then it is possible that Maya will crash.  This
	// is left as an exercise to the reader :-). 
	//
	if ( argData.isFlagSet(kLeftEyeCameraFlag) ) {
		// Assign the camera for the left eye
		// 
		MString camera; 
		argData.getFlagArgument( kLeftEyeCameraFlag, 0, camera );
		MDagPath theCamera; 
		MStatus status = getCameraFromString( camera, theCamera );
		if ( status == MS::kFailure ) { 
			return status; 
		}
		mpView->setLeftCamera( theCamera );
	} 
	if ( argData.isFlagSet(kRightEyeCameraFlag) ) {
		// Assign the camera for the right eye 
		//
		MString camera; 
		argData.getFlagArgument( kRightEyeCameraFlag, 0, camera );
		MDagPath theCamera; 
		MStatus status = getCameraFromString( camera, theCamera );
		if ( status == MS::kFailure ) { 
			return status; 
		}
		mpView->setRightCamera( theCamera );		
	} 
	if ( argData.isFlagSet(kCenterCameraFlag) ) {
		// Assign the center camera.  This camera represents the 
		// left & right camera when not in 3d view. 
		//
		MString camera; 
		argData.getFlagArgument( kCenterCameraFlag, 0, camera );
		MDagPath theCamera; 
		MStatus status = getCameraFromString( camera, theCamera );
		if ( status == MS::kFailure ) { 
			return status; 
		}
		mpView->setCenterCamera( theCamera );		
		mpView->setCamera( theCamera ); 
	}
	if ( argData.isFlagSet( kSwapBufferFlag ) ) { 
		mpView->swapLeftRightBuffer(); 
	}
	if ( argData.isFlagSet( kOverrideAdornmentDrawFlag ) ) { 
		bool override; 
		argData.getFlagArgument( kOverrideAdornmentDrawFlag, 0, override ); 
		mpView->setOverrideAdornmentDraw( override ); 
	}
	if ( argData.isFlagSet( kOverrideHUDDrawFlag ) ) { 
		bool override; 
		argData.getFlagArgument( kOverrideHUDDrawFlag, 0, override ); 
		mpView->setOverrideHUDDraw( override ); 
	}
	
	// Ask the parent class to process its flags. 
	//
	return ParentClass::doEditFlags();
}

MStatus stereoCameraViewCmd::doQueryFlags()
//
//	Description:
//		Don't do anything for the query.
//
{
	MPx3dModelView *user3dModelView = modelView();
	if (NULL == user3dModelView) {
		MGlobal::displayError("NULL == user3dModelView!");
        // Depending on your class structure, will dictate how you 
        // handle this case. If you have additional classes derived
        // from MPx3dModelViewCommand you should always call the
        // parent class doQueryFlags to allow base classes to handle
        // any flags.  In this case, returning MS::kUnknownParameter
        // tells the API that it should call the parent class.
        //
        return MS::kUnknownParameter;
	}

	if (user3dModelView->viewType() != "stereoCameraView") {
		MGlobal::displayError("This view is not a multiPackTest view");
		return MS::kFailure;
	}

	//	This is now safe to do, since the above test passed.
	//
	stereoCameraView *mpView = (stereoCameraView *)user3dModelView;
	
	MArgParser argData = parser();
	if ( argData.isFlagSet(kDisplayModeFlag) ) {
		stereoCameraView::DisplayMode mode = mpView->displayMode(); 
		switch (mode) { 
		case stereoCameraView::kLeftCamera: 
			setResult( MString(kLeftEye) ); 
			break; 
		case stereoCameraView::kRightCamera:
			setResult( MString(kRightEye) ); 
			break; 
		case stereoCameraView::kCenterCamera:
			setResult( MString(kCenterEye) );
			break; 
		case stereoCameraView::kStereo:
			setResult( MString(kStereoMode) ); 
			break; 
		default: 
			MGlobal::displayError( "Internal error: unrecognized mode!" ); 
		};
		return MS::kSuccess; 
	}

	// If the user asks for it, return the currently defined left, right,
	// or center cameras. 
	//
	if ( argData.isFlagSet(kLeftEyeCameraFlag) ) {
		MDagPath camera = mpView->leftCamera(); 
		setResult( camera.partialPathName() ); 
		return MS::kSuccess; 
	} 
	if ( argData.isFlagSet(kRightEyeCameraFlag) ) {
		MDagPath camera = mpView->rightCamera();
		setResult( camera.partialPathName() ); 
		return MS::kSuccess; 
	} 
	if ( argData.isFlagSet(kCenterCameraFlag) ) { 
		MDagPath camera = mpView->centerCamera(); 		
		setResult( camera.partialPathName() );		
		return MS::kSuccess; 
	}

	// Override draw settings ... 
	//
	if ( argData.isFlagSet(kOverrideAdornmentDrawFlag) ) { 
		setResult( mpView->overrideAdornmentDraw() );
		return MS::kSuccess; 
	}
	if ( argData.isFlagSet(kOverrideHUDDrawFlag) ) { 
		setResult( mpView->overrideHUDDraw() );
		return MS::kSuccess;
	}
	
	return ParentClass::doQueryFlags();
}

MString stereoCameraViewCmd::editorMenuScriptName() const
//
//  Description:
//   This script is called to setup menus. 
//
{
	return MString(kStereoCameraMenuScript);
}

MStatus stereoCameraViewCmd::getCameraFromString( 
	const MString &cameraName, MDagPath &cameraPath ) 
// 
// Description: 
//  Helper function that can take a camera name and return the corresponding
//  dag path. 
// 
{
	MSelectionList slist; 
	MStatus status = slist.add( cameraName );
	if ( status == MS::kSuccess ) { 
		status = slist.getDagPath( 0, cameraPath );
		if ( status == MS::kSuccess ) { 
			cameraPath.extendToShape(); 
			return status; 
		}
	}

	MGlobal::displayError( "Invalid camera name: " + cameraName ); 
	return status; 
}

const char * stereoCameraViewCmd::className()
{
	return "stereoCameraViewCmd";
}
